/* spfa + 01分数规划 二分
* 求负环常用方法
* (1) 统计每个点入队的次数，如果某个点入队n次，则说明存在负环。
      按照bfs算法，入队n次表示更新n次，说明最短路径至少包含n条边，至少n+1个点，所以一定有环
* (2)统计当前每个点的最短路中所包含的边数，如果某点的最短路所包含的边数大于等于n，则说明存在环。
      方法是额外维护一个cnt数组，记录每个点的最短路所包含的边数，当用中间点t更新了j是，cnt[j]应该比cnt[t]多1

      当所有点入队次数超过2n次，认为图中有很大可能存在负环
* 
*/
#pragma GCC optimize("O1,O2,O3,Ofast")
#pragma GCC optimize("no-stack-protector,unroll-loops,fast-math,inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,ssse3")

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
// #define ONLINE_GUDGE
using namespace std;
const int N = 1010, M = 5010, INF = 0x3f3f3f3f;

int n, m;
int wf[N];
double dist[N]; //
int fa[N], cnt[N];
bool st[N];

int e[M], ne[M], h[N], wt[M], idx;
void AddEdge(int a, int b, int c)
{ e[idx] = b, ne[idx] = h[a], wt[idx] = c, h[a] = idx++; }

int find(int x){    //并查集找根节点
    return fa[x] = (fa[x] == x ? x : find(fa[x]));
}

bool spfa(double mid) // 是否存在正环（最长路），是否存在负环（最短路）
{
    memset(dist, 0, sizeof dist);
    memset(cnt, 0, sizeof cnt);
    memset(st, 0, sizeof st);
    queue<int> q;
    
    for(int i = 1; i <= n; i++)
    {
        q.push(i);
        st[i] = true;
    }

    while(q.size())
    {
        int u = q.front(); q.pop();
        st[u] = false;

        for(int i = h[u]; ~i; i = ne[i])
        {
            int v = e[i];
            //将这条边转化后的边权值
            double w = wf[u] - wt[i] * mid;//注意边权转化时wf的下标是边的起点值,wt下标是边的指针值
            //这里求是否存在正环，因此spfa从寻找“最短路”改为寻找“最长路”
            if(dist[v] < dist[u] + w)
            {
                
                // dist[v] = dist[u] + wf[u] - mid * wt[i];
                dist[v] = dist[u] + w;
                cnt[v] =  cnt[u] + 1; // j点的最短路径上边的数量是t点对应的加1，多了枚举的这条
                if(cnt[v] >= n) return true; //n条边 n+1个点 一定有重复的
                if(!st[v])
                {
                    q.push(v);
                    st[v] = true;
                }
            }
            //printf("u: %d r: %d\n", u, v);
            //printf("cnt[]: "); for(int i = 0; i <= n; i++) printf("%d ", cnt[i]);
            //cout << endl;
            // printf("dist[]: "); for(int i = 0; i <= n; i++) printf("%d ", dist[i]);
            //cout << endl;
        }
    }
    return false;
}

int main()
{
    #ifdef ONLINE_JUDGE

    #else
        freopen("./in.txt", "r", stdin);
    #endif

    ios::sync_with_stdio(0); cin.tie(0);
    int T; T = 1; // cin >> T;
    while(T--){
        memset(h,-1,sizeof h);
        idx=0;
        cin >> n >> m;
        for(int i = 1;i<=n;i++) cin >> wf[i]; // 点权

        while(m--){ // m条有向边
            int a, b, c; cin >> a >> b >> c;
            AddEdge(a, b, c); 
        }
        double l = 0, r = 1000;
        while(r - l > 1e-4){ // 误差
            double mid = (l + r) / 2; // 二分sum(f[i])/sum(t[i]) > mid -> sum(f[i] - mid*t[i]) > 0 -> 每条边的权值是f[i]-mid*t[i]
            // printf("l: %lf  r: %lf  mid: %lf\n", l, r, mid);
            if(spfa(mid)) l = mid;
            else r = mid;
        }

        printf("%.2lf\n", r);
    }
    
    return 0;
}